package com.rgs.base.core.util.excel.bo;

import cn.hutool.core.collection.CollectionUtil;
import com.google.common.base.Joiner;
import com.google.common.base.Strings;
import com.google.common.collect.Sets;
import com.rgs.base.core.util.excel.ExcelColumnAnnotation;
import lombok.Data;
import lombok.extern.slf4j.Slf4j;

import java.io.Serializable;
import java.lang.reflect.Field;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.HashSet;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
import java.util.Optional;
import java.util.Set;
import java.util.stream.Collectors;

/**
 * @author Ren Gaoshuai
 * @date 2022-03-08 15:45
 **/
@Data
@Slf4j
public class FieldExcelColumnBO implements IExcelColumnBO, Serializable {


    private LinkedList<Field> fieldList;
    private LinkedList<ExcelColumnAnnotation> columnNameMerge;
    //
    private Boolean isMapType;
    //
    private Set<String> ignoreTagSet;

    //
    private Integer orderNumber;

    private List<String> extendColumnMerge;


    private Integer originOrderNumber;

    private List<String> originExtendColumnMerge;


    private String columnName;

    public FieldExcelColumnBO(Field field, ExcelColumnAnnotation excelColumn) {
        fieldList = new LinkedList<>();
        columnNameMerge = new LinkedList<>();
        ignoreTagSet = new HashSet<>();
        orderNumber = excelColumn.orderNumber();
        extendColumnMerge = new ArrayList<>(0);
        this.addFirst(field, excelColumn);
        columnName = excelColumn.columnName();
        //
    }

    @Override
    public List<String> getColumnMergeList() {
        List<String> collect = columnNameMerge.stream()
                .flatMap(q -> Arrays.asList(q.columnMerge()).stream())
                .collect(Collectors.toList());
        collect.addAll(extendColumnMerge);
        return collect;
    }

    public void addFirst(Field field, ExcelColumnAnnotation excelColumn) {
        this.addFirstField(field);
        this.addFirstColumnNameMerge(excelColumn);

    }

    public void unionExcelDynamicHead(ExcelDynamicHeadBO excelDynamicHead) {
        Optional<Integer> originNumber = Optional.ofNullable(this.originOrderNumber);
        if (originNumber.isPresent()) {
            //如果静态排序，则originOrderNumber有值
            this.orderNumber = this.orderNumber + excelDynamicHead.getOrderNumber() +
                    originNumber.orElse(0);
        } else {
            //如果动态排序，则originOrderNumber无值
            this.orderNumber = excelDynamicHead.getOrderNumber();
        }

        if (CollectionUtil.isEmpty(this.originExtendColumnMerge)) {
            this.originExtendColumnMerge = new ArrayList<>(0);
        }
        this.extendColumnMerge =
                new ArrayList<>(this.originExtendColumnMerge.size() +
                        excelDynamicHead.getColumnMerge().size());
        this.extendColumnMerge.addAll(this.originExtendColumnMerge);
        this.extendColumnMerge.addAll(excelDynamicHead.getColumnMerge());
        if (!Strings.isNullOrEmpty(excelDynamicHead.getColumnName())) {
            this.columnName = excelDynamicHead.getColumnName();
        }
    }


    private void addFirstField(Field field) {
        fieldList.addFirst(field);
        this.isMapType = field.getType().isAssignableFrom(Map.class);
    }

    private void addFirstColumnNameMerge(ExcelColumnAnnotation excelColumn) {
        columnNameMerge.addFirst(excelColumn);
        ignoreTagSet.addAll(Arrays.asList(excelColumn.ignoreTag()));
        orderNumber += excelColumn.orderNumber();
    }

    @Override
    public String getColumnName() {

        return this.columnName;
//        return columnNameMerge.getLast().columnName();
    }

    @Override
    public String getFieldName() {
        return Joiner.on('.')
                .join(fieldList.stream().map(Field::getName)
                        .collect(Collectors.toList()));
    }

    public Object getValue(Object obj) {
        try {
            obj = fieldList.get(0).get(obj);
            for (int i = 1; i < fieldList.size(); i++) {
                obj = fieldList.get(i).get(obj);
            }
            return obj;
        } catch (IllegalAccessException exc) {
            log.error(exc.getMessage());
            return null;
        } catch (NullPointerException e) {
            log.error(e.getMessage());
            return null;
        }
    }

    public boolean isIgnore(Set<String> ignoreSet) {
        Sets.SetView<String> intersectionSet = Sets.intersection(ignoreTagSet, ignoreSet);
        return intersectionSet.immutableCopy().size() > 0;
    }

    public void originBak() {
        this.extendColumnMerge = this.originExtendColumnMerge;
        this.orderNumber = this.orderNumber + Optional.ofNullable(this.originOrderNumber).orElse(0);
    }
}
